home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library / Microsoft Programmer's Library (CD-ROM Database)(125-099-008)(Version 1.1a)(CDRM 162100)(1989).iso / SAMPCODE / OS2SDK11 / TK4 / LINEFRAC / LFTHREAD.C < prev    next >
C/C++ Source or Header  |  1989-02-20  |  16KB  |  531 lines

  1. /************************************************************************
  2. *
  3. *   lfthread.c -- Subroutines for thread management for LineFractal.
  4. *
  5. *   Created by Microsoft Corporation, 1989
  6. *
  7. ************************************************************************/
  8.  
  9. #define INCL_WIN
  10. #define INCL_GPI
  11. #define INCL_DOSSEMAPHORES
  12. #define INCL_DOSMEMMGR
  13. #define INCL_DOSPROCESS
  14. #define INCL_DOSERRORS
  15. #include <os2.h>
  16.  
  17. #include <mt\process.h>
  18. #include <mt\stddef.h>
  19.  
  20. #define INCL_GLOBALS
  21. #define INCL_THREADS
  22. #include "linefrac.h"
  23.  
  24. #define INCL_LFCMD
  25. #define INCL_LFMAIN
  26. #define INCL_LFPS
  27. #define INCL_LFUTIL
  28. #define INCL_LFTHREAD
  29. #define INCL_LFDRAW
  30. #include "lffuncs.h"
  31.  
  32.  
  33.  
  34.  
  35. /************************************************************************
  36. *
  37. *   Global Variables
  38. *
  39. ************************************************************************/
  40.  
  41. extern GLOBALDATA global;
  42.  
  43.  
  44.  
  45.  
  46. /************************************************************************
  47. *
  48. *   LfStartThread
  49. *
  50. *   Do everything needed to start up a background thread drawing
  51. *   fractals.
  52. *
  53. *   This includes:
  54. *
  55. *    Allocate space for thread structure.
  56. *    Initialize fields of thread structure.
  57. *    Create a presentation space for the thread.
  58. *    Create stack space for the thread.
  59. *    Set the thread's semaphore to block -- i.e. don't start
  60. *        drawing until everything is ready.
  61. *    Start the thread.
  62. *    Set the thread's priority to idle time.
  63. *
  64. ************************************************************************/
  65.  
  66. #define SIZE_ACCUM_STACK    2048
  67.  
  68. PTHR
  69. LfStartThread(dcType)
  70. USHORT dcType;
  71. {
  72.     PTHR pthr;
  73.  
  74.  
  75.     pthr = NULL;    /* zero out all 32 bits */
  76.     if (DosAllocSeg(sizeof(THR), ((PUSHORT)&pthr)+1, 0))
  77.     return NULL;
  78.  
  79.     pthr->dcType = dcType;
  80.  
  81.     LfPreInitThread(pthr);
  82.     if (LfCreatePS(pthr))
  83.     {
  84.     LfPostInitThread(pthr);
  85.     if (DosAllocSeg(SIZE_ACCUM_STACK, &pthr->selStack, 0))
  86.         goto lfst_exit;
  87.  
  88.     DosSemSet(&pthr->lSemRedraw);
  89.     pthr->tid = _beginthread(LineFractalThread, MAKEP(pthr->selStack, 0), SIZE_ACCUM_STACK, pthr);
  90.     if (pthr->tid == -1)
  91.     {
  92.         LfDeletePS(pthr);
  93.         goto lfst_exit;
  94.     }
  95.     DosSetPrty(PRTYS_THREAD, PRTYC_IDLETIME, 0, pthr->tid);
  96.  
  97.     LfSelectXform(global.hwnd, pthr, pthr->usCurXform);
  98.     DosSemClear(&pthr->lSemRedraw);
  99.  
  100.     if (!DevQueryCaps(pthr->hdc, CAPS_HORIZONTAL_RESOLUTION, 2L, (PLONG)&(pthr->AspectRatio)))
  101.     {
  102.         pthr->AspectRatio.lHorz = 1L;
  103.         pthr->AspectRatio.lVert = 1L;
  104.     }
  105.  
  106.     return pthr;
  107.     }
  108. lfst_exit:
  109.     DosFreeSeg(*(((PUSHORT)&pthr)+1));
  110.     return NULL;
  111. }
  112.  
  113.  
  114.  
  115.  
  116. /************************************************************************
  117. *
  118. *   LfPreInitThread
  119. *
  120. *   Initialize constant values in the thread structure needed from
  121. *   the moment the thread starts.  If thread inheritance is enabled,
  122. *   then copy as much as possible from the top thread, if there is
  123. *   one.
  124. *
  125. ************************************************************************/
  126.  
  127. VOID
  128. LfPreInitThread(pthr)
  129. PTHR pthr;
  130. {
  131.     pthr->hps        = NULL;
  132.     pthr->hdc        = NULL;
  133.     pthr->hbm        = NULL;
  134.     pthr->fTimeToDie    = FALSE;
  135.     pthr->fUpdateAttrs    = FALSE;
  136.     pthr->fBusy     = FALSE;
  137.     pthr->pptl        = NULL;
  138.     pthr->cptl        = 0;
  139.     pthr->pmatlf    = NULL;
  140.  
  141.     if (global.fThreadInheritance && global.pThrTop)
  142.     {
  143.     pthr->cPlanes           = global.pThrTop->cPlanes      ;
  144.     pthr->cBitCount        = global.pThrTop->cBitCount      ;
  145.  
  146.     pthr->cxWCS           = global.pThrTop->cxWCS          ;
  147.     pthr->cyWCS           = global.pThrTop->cyWCS          ;
  148.  
  149.     pthr->fAutoSizePS      = global.pThrTop->fAutoSizePS      ;
  150.     pthr->fAutoSelectDims  = global.pThrTop->fAutoSelectDims  ;
  151.     pthr->fClearOnRedraw   = global.pThrTop->fClearOnRedraw   ;
  152.     pthr->fAutoStartRedraw = global.pThrTop->fAutoStartRedraw ;
  153.     pthr->fCollectBounds   = global.pThrTop->fCollectBounds   ;
  154.  
  155.     pthr->fFracRedraw      = global.pThrTop->fFracRedraw      ;
  156.     pthr->fPrimRedraw      = global.pThrTop->fPrimRedraw      ;
  157.     pthr->fAttrRedraw      = global.pThrTop->fAttrRedraw      ;
  158.  
  159.     pthr->lb           = global.pThrTop->lb          ;
  160.     pthr->flLineAttrs      = LFA_LINEALL              ;
  161.     pthr->mb           = global.pThrTop->mb          ;
  162.     pthr->flMarkerAttrs    = LFA_MARKALL              ;
  163.     pthr->ab           = global.pThrTop->ab          ;
  164.     pthr->flAreaAttrs      = LFA_AREAALL              ;
  165.     pthr->ib           = global.pThrTop->ib          ;
  166.     pthr->flImageAttrs     = LFA_IMAGEALL              ;
  167.  
  168.     pthr->usCurPrim        = global.pThrTop->usCurPrim      ;
  169.     pthr->usCurXform       = global.pThrTop->usCurXform      ;
  170.     pthr->usRecursion      = global.pThrTop->usRecursion      ;
  171.     pthr->usPolygonSides   = global.pThrTop->usPolygonSides   ;
  172.     pthr->cptMax           = global.pThrTop->cptMax       ;
  173.     pthr->dblXOff           = global.pThrTop->dblXOff      ;
  174.     pthr->dblYOff           = global.pThrTop->dblYOff      ;
  175.     pthr->dblXScale        = global.pThrTop->dblXScale      ;
  176.     pthr->dblYScale        = global.pThrTop->dblYScale      ;
  177.     pthr->dblRotation      = global.pThrTop->dblRotation      ;
  178.     pthr->flMiscAttrs      = LFA_MISCALL              ;
  179.     }
  180.     else
  181.     {
  182.     pthr->cPlanes           = global.bm.cPlanes;
  183.     pthr->cBitCount        = global.bm.cBitCount;
  184.  
  185.     pthr->cxWCS           = 10000L;
  186.     pthr->cyWCS           = 10000L;
  187.  
  188.     pthr->fAutoSizePS      = TRUE;
  189.     pthr->fAutoSelectDims  = TRUE;
  190.     pthr->fClearOnRedraw   = TRUE;
  191.     pthr->fAutoStartRedraw = FALSE;
  192.     pthr->fCollectBounds   = TRUE;
  193.  
  194.     pthr->fFracRedraw      = TRUE;
  195.     pthr->fPrimRedraw      = TRUE;
  196.     pthr->fAttrRedraw      = TRUE;
  197.  
  198.     pthr->lb.lColor        = CLR_NEUTRAL;
  199.     pthr->lb.usMixMode     = FM_OVERPAINT;
  200.     pthr->lb.fxWidth       = LINEWIDTH_NORMAL;
  201. ;     pthr->lb.lGeomWidth    = 1L;
  202.     pthr->lb.usType        = LINETYPE_SOLID;
  203. ;     pthr->lb.usEnd     = LINEEND_FLAT;
  204. ;     pthr->lb.usJoin    = LINEJOIN_BEVEL;
  205.     pthr->flLineAttrs      = LFA_LINEALL;
  206.  
  207.     pthr->mb.lColor        = CLR_NEUTRAL;
  208.     pthr->mb.lBackColor    = CLR_BACKGROUND;
  209.     pthr->mb.usMixMode     = FM_OVERPAINT;
  210.     pthr->mb.usBackMixMode = BM_LEAVEALONE;
  211.     pthr->mb.usSet           = LCID_DEFAULT;
  212.     pthr->mb.usSymbol      = MARKSYM_DIAMOND;
  213. ;     pthr->mb.sizfxCell.cx    = 0L;
  214. ;     pthr->mb.sizfxCell.cy    = 0L;
  215.     pthr->flMarkerAttrs    = LFA_MARKALL;
  216.  
  217.     pthr->ab.lColor        = CLR_NEUTRAL;
  218.     pthr->ab.lBackColor    = CLR_BACKGROUND;
  219.     pthr->ab.usMixMode     = FM_OVERPAINT;
  220.     pthr->ab.usBackMixMode = BM_OVERPAINT;
  221.     pthr->ab.usSet           = LCID_DEFAULT;
  222.     pthr->ab.usSymbol      = PATSYM_NOSHADE;
  223. ;     pthr->ab.ptlRefPoint.x = 0L;
  224. ;     pthr->ab.ptlRefPoint.y = 0L;
  225.     pthr->flAreaAttrs      = LFA_AREAALL;
  226.  
  227.     pthr->ib.lColor        = CLR_NEUTRAL;
  228.     pthr->ib.lBackColor    = CLR_BACKGROUND;
  229.     pthr->ib.usMixMode     = FM_OVERPAINT;
  230.     pthr->ib.usBackMixMode = FM_OVERPAINT;
  231.     pthr->flImageAttrs     = LFA_IMAGEALL;
  232.  
  233.     pthr->usCurPrim        = IDM_POLYLINE;
  234.     pthr->usCurXform       = IDM_SAWTOOTH;
  235.     pthr->usRecursion      = 1;
  236.     pthr->usPolygonSides   = 3;
  237.     pthr->cptMax           = MAX_POINT_COUNT;
  238.     pthr->dblXOff           = 0.125;
  239.     pthr->dblYOff           = 0.5;
  240.     pthr->dblXScale        = 0.75;
  241.     pthr->dblYScale        = 0.75;
  242.     pthr->dblRotation      = 0.0;
  243.     pthr->flMiscAttrs      = LFA_MISCALL;
  244.     }
  245.  
  246. }
  247.  
  248.  
  249.  
  250.  
  251. /************************************************************************
  252. *
  253. *   LfPostInitThread
  254. *
  255. *   Initialize various values in the thread structure which required
  256. *   that a PS/DC/BM had been created.  If thread inheritance is enabled,
  257. *   then copy as much as possible from the top thread, if there is
  258. *   one.
  259. *
  260. ************************************************************************/
  261.  
  262. VOID
  263. LfPostInitThread(pthr)
  264. PTHR pthr;
  265. {
  266.     if (!(global.fThreadInheritance && global.pThrTop))
  267.     {
  268.     pthr->lb.lGeomWidth = GpiQueryLineWidthGeom(pthr->hps);
  269.     pthr->lb.usEnd        = (USHORT) GpiQueryLineEnd(pthr->hps);
  270.     pthr->lb.usJoin     = (USHORT) GpiQueryLineJoin(pthr->hps);
  271.  
  272.     DevQueryCaps(pthr->hdc, CAPS_MARKER_WIDTH,  1L, (PLONG)&(pthr->mb.sizfxCell.cx));
  273.     DevQueryCaps(pthr->hdc, CAPS_MARKER_HEIGHT, 1L, (PLONG)&(pthr->mb.sizfxCell.cy));
  274.  
  275.     GpiQueryPatternRefPoint(pthr->hps,&(pthr->ab.ptlRefPoint));
  276.     }
  277. }
  278.  
  279.  
  280.  
  281.  
  282. /************************************************************************
  283. *
  284. *   LfKillThread
  285. *
  286. *   Force the given thread to die and release its resources.
  287. *
  288. ************************************************************************/
  289.  
  290. VOID
  291. LfKillThread(pthr)
  292. PTHR pthr;
  293. {
  294.     int i, j;
  295.  
  296.  
  297.     /* This does not do anything if there aren't any threads. */
  298.  
  299.     if (global.cThr && pthr)
  300.     {
  301.     /****************************************************************
  302.     *  Tell the thread to die when it can.
  303.     *  If blocked on lSemRedraw, then it will recognize fTimeToDie
  304.     *  as soon as it's unblocked.  If it's currently drawing,
  305.     *  it will recognize fInterrupted, kick out of the recursion,
  306.     *  loop back up to check lSemRedraw, which will be clear, so
  307.     *  it'll do as already mentioned.  Set the priority to time-
  308.     *  critical to speed things up.
  309.     ****************************************************************/
  310.  
  311.     pthr->fTimeToDie   = TRUE;
  312.     pthr->fInterrupted = TRUE;
  313.     DosSetPrty(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, pthr->tid);
  314.     DosSemClear(&pthr->lSemRedraw);
  315.  
  316.  
  317.     /****************************************************************
  318.     *  Once it's decided it must die, it will clean up after
  319.     *  itself and exit quietly.  To detect when it has actually
  320.     *  exited, so that we can safely free up the stack, we will
  321.     *  loop asking for the thread's priority until an error occurs.
  322.     *  We will assume that an error implies the thread has exited.
  323.     ****************************************************************/
  324.  
  325.     {
  326.         USHORT usT;
  327.         USHORT usRet;
  328.         while (!(usRet = DosGetPrty(PRTYS_THREAD, &usT, pthr->tid)));
  329.         if (usRet != ERROR_INVALID_THREADID)
  330.         {
  331.         MyMessageBox(global.hwnd,
  332.             "Cannot kill thread");
  333.         return;
  334.         }
  335.     }
  336.  
  337.  
  338.     /****************************************************************
  339.     *  Extract the given thread from the group. This is done
  340.     *  inside a critical section because the drawing threads
  341.     *  call LfIsThreadTop, which reads global.aThr.
  342.     ****************************************************************/
  343.  
  344.     i = 0;
  345.     while ((i < global.cThr) && (pthr != global.aThr[i]))
  346.         ++i;    /* if i == global.cThr we have a problem */
  347.     DosEnterCritSec();
  348.     for (j = i; j < global.cThr-1; ++j)
  349.         global.aThr[j] = global.aThr[j+1];
  350.     global.aThr[j] = NULL;    /* clear out all copies of pthr */
  351.     --global.cThr;
  352.     DosExitCritSec();
  353.  
  354.  
  355.     /****************************************************************
  356.     *  Free up resources allocated for the thread.
  357.     ****************************************************************/
  358.  
  359.     LfDeletePS(pthr);
  360.     DosFreeSeg(pthr->selStack);
  361.     DosFreeSeg(*(((PUSHORT)&pthr)+1));
  362.     }
  363. }
  364.  
  365.  
  366.  
  367.  
  368. /************************************************************************
  369. *
  370. *   LfBringThreadToTop
  371. *
  372. *   Bring the specified thread to the top, and invalidate the window
  373. *   to force a WM_PAINT message to make the thread's image visible.
  374. *   The given thread can be NULL, in which case just set pThrTop to
  375. *   NULL.
  376. *
  377. ************************************************************************/
  378.  
  379. VOID
  380. LfBringThreadToTop(pthr)
  381. PTHR pthr;
  382. {
  383.     int i;
  384.  
  385.  
  386.     /********************************************************************
  387.     *  Find the given thread in the group.
  388.     ********************************************************************/
  389.  
  390.     if (pthr)
  391.     {
  392.     i = 0;
  393.     while ((i < global.cThr) && (pthr != global.aThr[i]))
  394.         ++i;    /* if i == global.cThr, we have problems */
  395.     }
  396.     else
  397.     i = 32767; /* should cause gp fault if used */
  398.  
  399.  
  400.     /********************************************************************
  401.     *  If the user wants the menu items updated, and we're switching
  402.     *  away from an active thread, then uncheck the current thread's
  403.     *  settings.
  404.     ********************************************************************/
  405.  
  406.     if (global.fUpdateMenusOnThreadSwitch)
  407.     {
  408.     if (global.pThrTop)
  409.     {
  410.         UNCHECK_MENU_ITEM(global.hwndFrame, IDM_AUTORESIZE);
  411.         UNCHECK_MENU_ITEM(global.hwndFrame, IDM_AUTOSELECTDIMS);
  412.         UNCHECK_MENU_ITEM(global.hwndFrame, IDM_CLEARONREDRAW);
  413.         UNCHECK_MENU_ITEM(global.hwndFrame, IDM_AUTOSTARTREDRAW);
  414.         UNCHECK_MENU_ITEM(global.hwndFrame, IDM_COLLECTBOUNDS);
  415.         UNCHECK_MENU_ITEM(global.hwndFrame, IDM_FRACREDRAW);
  416.         UNCHECK_MENU_ITEM(global.hwndFrame, IDM_PRIMREDRAW);
  417.         UNCHECK_MENU_ITEM(global.hwndFrame, IDM_ATTRREDRAW);
  418.         UNCHECK_MENU_ITEM(global.hwndFrame, global.pThrTop->usCurPrim);
  419.         UNCHECK_MENU_ITEM(global.hwndFrame, global.pThrTop->usCurXform);
  420.         UNCHECK_MENU_ITEM(global.hwndFrame, global.pThrTop->dcType);
  421.     }
  422.     }
  423.  
  424.  
  425.     /********************************************************************
  426.     *  Switch the given thread to the top.
  427.     ********************************************************************/
  428.  
  429.     DosEnterCritSec();
  430.     global.iThrTop = i;
  431.     global.pThrTop = pthr;
  432.     DosExitCritSec();
  433.  
  434.  
  435.     /********************************************************************
  436.     *  If we switched in a living thread, then invalidate the entire
  437.     *  window.    This will cause a WM_PAINT message to be sent, which
  438.     *  will display the image from the new top thread.    If the user
  439.     *  has not disabled updating of the menus, then do that.
  440.     ********************************************************************/
  441.  
  442.     if (pthr)
  443.     {
  444.     WinInvalidateRect(global.hwnd, NULL, FALSE);
  445.  
  446.     /* If the user wants menu items updated, then do it now. */
  447.     if (global.fUpdateMenusOnThreadSwitch)
  448.     {
  449.         TOGGLE_MENU_ITEM(global.hwndFrame, IDM_AUTORESIZE,       pthr->fAutoSizePS);
  450.         TOGGLE_MENU_ITEM(global.hwndFrame, IDM_AUTOSELECTDIMS,  pthr->fAutoSelectDims);
  451.         TOGGLE_MENU_ITEM(global.hwndFrame, IDM_CLEARONREDRAW,   pthr->fClearOnRedraw);
  452.         TOGGLE_MENU_ITEM(global.hwndFrame, IDM_AUTOSTARTREDRAW, pthr->fAutoStartRedraw);
  453.         TOGGLE_MENU_ITEM(global.hwndFrame, IDM_COLLECTBOUNDS,   pthr->fCollectBounds);
  454.         TOGGLE_MENU_ITEM(global.hwndFrame, IDM_FRACREDRAW,       pthr->fFracRedraw);
  455.         TOGGLE_MENU_ITEM(global.hwndFrame, IDM_PRIMREDRAW,       pthr->fPrimRedraw);
  456.         TOGGLE_MENU_ITEM(global.hwndFrame, IDM_ATTRREDRAW,       pthr->fAttrRedraw);
  457.         CHECK_MENU_ITEM (global.hwndFrame, pthr->usCurPrim);
  458.         CHECK_MENU_ITEM (global.hwndFrame, pthr->usCurXform);
  459.         CHECK_MENU_ITEM (global.hwndFrame, pthr->dcType);
  460.  
  461.         LfUpdateThreadMenu();
  462.     }
  463.     }
  464. }
  465.  
  466.  
  467.  
  468.  
  469. /************************************************************************
  470. *
  471. *   LfIsThreadTop
  472. *
  473. *   Returns TRUE if the given thread is the top one.  Putting this
  474. *   test in a function isolates it and makes it easier to maintain
  475. *   a critical section.
  476. *
  477. ************************************************************************/
  478.  
  479. BOOL
  480. LfIsThreadTop(pthr)
  481. PTHR pthr;
  482. {
  483.     BOOL f;
  484.  
  485.     f = FALSE;
  486.     DosEnterCritSec();
  487.     if (pthr == global.pThrTop)
  488.     f = TRUE;
  489.     DosExitCritSec();
  490.  
  491.     return f;
  492. }
  493.  
  494.  
  495.  
  496.  
  497. /************************************************************************
  498. *
  499. *   LfUpdateThreadMenu
  500. *
  501. *   Brings the "Thread Bring thread to top" submenu in line with the
  502. *   currently active threads.
  503. *
  504. ************************************************************************/
  505.  
  506. VOID
  507. LfUpdateThreadMenu()
  508. {
  509.     /*
  510.      * Enable the numbers for threads that do exist.
  511.      * Disable the numbers for threads that don't exist.
  512.      * Uncheck everything, then check the right one.
  513.      */
  514.  
  515.     int i;
  516.  
  517.     for (i = 0; i < global.cThr; ++i)
  518.     {
  519.     UNCHECK_MENU_ITEM(global.hwndFrame, IDM_THR0TOTOP+i);
  520.     ENABLE_MENU_ITEM (global.hwndFrame, IDM_THR0TOTOP+i);
  521.     }
  522.  
  523.     for (     ; i < MAX_THREADS; ++i)
  524.     {
  525.     UNCHECK_MENU_ITEM(global.hwndFrame, IDM_THR0TOTOP+i);
  526.     DISABLE_MENU_ITEM(global.hwndFrame, IDM_THR0TOTOP+i);
  527.     }
  528.  
  529.     CHECK_MENU_ITEM(global.hwndFrame, IDM_THR0TOTOP + global.iThrTop);
  530. }
  531.